﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.ComponentModel;
using TED.ViewModels;
using System.Windows.Threading;

namespace TED.Model
{
    public class SyncJobsClass
    {
        public delegate void RunElementDelegate(string parameter);
        private int numberOfPages = 7;

        public class Job
        {
            public RunElementDelegate Function { get; set; }
            public string Parameter { get; set; }
        }

        public List<Job> ElementsToRun = new List<Job>();

        public int CurrentElementToRun = 0;
        public BackgroundWorker Worker;
        public int JobsCount
        {
            get { return ElementsToRun.Count; }
        }

        public delegate void ElementFinishedDelegate();
        public event ElementFinishedDelegate ElementFinished;

        public delegate void WorkFinishedDelegate(bool success);
        public event WorkFinishedDelegate WorkFinished;

        public SyncJobsClass()
        {
            Items = new ObservableCollection<TEDVideo>();
            Worker = new BackgroundWorker();
            Worker.WorkerSupportsCancellation = true;
            Worker.DoWork += new DoWorkEventHandler(Worker_DoWork);
            this.ElementFinished += new ElementFinishedDelegate(SyncJobsClass_ElementFinished);
        }

        void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            if (CurrentElementToRun < ElementsToRun.Count)
            {
                RunElementDelegate function = new RunElementDelegate(ElementsToRun[CurrentElementToRun].Function);
                function(ElementsToRun[CurrentElementToRun].Parameter);
                
            }
        }

        void SyncJobsClass_ElementFinished()
        {
            CurrentElementToRun++;

            if (CurrentElementToRun > ElementsToRun.Count - 1)
            {
                Worker.CancelAsync();
                WorkFinished(true);
                return;
            }

            RunElementDelegate function = new RunElementDelegate(ElementsToRun[CurrentElementToRun].Function);
            function(ElementsToRun[CurrentElementToRun].Parameter);
        }

        //Parse www.ted.com/talks
        #region ParseTEDTalks
        public void Parse()
        {
            this.CurrentElementToRun = 0;
            this.ElementsToRun = new List<Job>();

            for (int i = 1; i <= numberOfPages; ++i)
            {
                Job job = new Job();
                job.Function = ParseTEDTalks;
                job.Parameter = i.ToString();
                this.ElementsToRun.Add(job);
            }

            this.Worker.RunWorkerAsync();

        }
        /// <summary>
        /// Parse TED website using a simpler method: WebClient
        /// </summary>
        /// <param name="i">the page number</param>
        public void ParseTEDTalks(string i)
        {
            WebClient c = new WebClient();
            string TEDUrl = "http://www.ted.com/talks/list/page/" + i;
            c.DownloadStringAsync(new Uri(TEDUrl));
            c.DownloadStringCompleted += new DownloadStringCompletedEventHandler(c_DownloadStringCompleted);
        }

        /// <summary>
        /// Handle html that is returned from TED website
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void c_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                Worker.CancelAsync();
                this.WorkFinished(false);
            }
            lock (this)
            {
                string responseString = e.Result;

                ParseHTML(responseString);
                ElementFinished();
            }

        }


        /// <summary>
        /// Parse HTML from TED
        /// </summary>
        /// <param name="responseString">string returned from server</param>
        private void ParseHTML(string responseString)
        {
            //Begin parsing code
            int iFirst = responseString.IndexOf("<div class=\"talkListContainer");
            int iLast = responseString.IndexOf("<div class=\"pagination clearfix\">");
            int iLength = iLast - iFirst;
            responseString = responseString.Substring(iFirst, iLength);

            //Replace "&amp" by "&"
            string oldChar = "&amp";
            responseString = responseString.Replace(oldChar, "&");
            Console.Write(responseString);

            // Now, parse html to get Title & URL of each Talk
            string regexLinkPattern = @"<a.*?title=[""'](?<title>.*?)[""'].*?href=[""'](?<url>.*?)[""'].*?>.*?<img.*?<img.*?alt=[""'].*?[""'].*?src=[""'](?<imageUrl>.*?)[""'].*?/>";
            MatchCollection hyperlinkMatches = Regex.Matches(responseString, regexLinkPattern);

            string[] matchURL = new string[hyperlinkMatches.Count];
            string[] matchTitle = new string[hyperlinkMatches.Count];
            string[] matchImage = new string[hyperlinkMatches.Count];

            foreach (System.Text.RegularExpressions.Match match in hyperlinkMatches)
            {
                String description = match.Groups["title"].Value;
                int indexOf = description.IndexOf(":");

                Items.Add(new TEDVideo
                {
                    Title = description.Substring(indexOf + 2),
                    Author = description.Substring(0, Math.Max(indexOf, 0)),
                    ViewUrl = "/Video.xaml?url=" + match.Groups["url"].Value,
                    ImageUrl = new Uri(match.Groups["imageUrl"].Value, UriKind.Absolute)

                });
            }

                this.NotifyPropertyChanged("Items");
        }
        #endregion

        //Collection
        #region VideoItems

        public ObservableCollection<TEDVideo> _items;
        public ObservableCollection<TEDVideo> Items
        {
            get { return _items; }
            private set
            {
                if (Items == value)
                {
                    return;
                }

                _items = value;
                this.NotifyPropertyChanged("Items");
            }
        }
        #endregion

        // Utility

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        #endregion
    }
}